package com.ihr360.job.core.item.database.support;

import com.ihr360.job.core.repository.support.DatabaseType;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.jdbc.support.incrementer.H2SequenceMaxValueIncrementer;
import org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer;
import org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer;
import org.springframework.util.ReflectionUtils;

import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import static com.ihr360.job.core.repository.support.DatabaseType.H2;
import static com.ihr360.job.core.repository.support.DatabaseType.HSQL;
import static com.ihr360.job.core.repository.support.DatabaseType.MYSQL;

/**
 * Default implementation of the {@link DataFieldMaxValueIncrementerFactory}
 * interface. Valid database types are given by the {@link DatabaseType} enum.
 *
 * @author Lucas Ward
 * @author Thomas Risberg
 * @see DatabaseType
 */
public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxValueIncrementerFactory {

    private DataSource dataSource;

    private String incrementerColumnName = "ID";

    /**
     * Public setter for the column name (defaults to "ID") in the incrementer.
     * Only used by some platforms (Derby, HSQL, MySQL, SQL Server and Sybase),
     * and should be fine for use with Spring Batch meta data as long as the
     * default batch schema hasn't been changed.
     *
     * @param incrementerColumnName the primary key column name to set
     */
    public void setIncrementerColumnName(String incrementerColumnName) {
        this.incrementerColumnName = incrementerColumnName;
    }

    public DefaultDataFieldMaxValueIncrementerFactory(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public DataFieldMaxValueIncrementer getIncrementer(String incrementerType, String incrementerName) {
        DatabaseType databaseType = DatabaseType.valueOf(incrementerType.toUpperCase());

        if (databaseType == HSQL) {
            return new HsqlMaxValueIncrementer(dataSource, incrementerName, incrementerColumnName);
        }
        else if (databaseType == H2) {
            return new H2SequenceMaxValueIncrementer(dataSource, incrementerName);
        }
        else if (databaseType == MYSQL) {
            DataFieldMaxValueIncrementer incr = new MySQLMaxValueIncrementer(dataSource, incrementerName, incrementerColumnName);
            // set MySQLMaxValueIncrementer#setUseNewConnection to true for Spring 4.3.6 and later
            Method m = ReflectionUtils.findMethod(incr.getClass(), "setUseNewConnection", boolean.class);
            if (m != null) {
                ReflectionUtils.makeAccessible(m);
                ReflectionUtils.invokeMethod(m, incr, true);
            }
            return incr;
        }
        throw new IllegalArgumentException("databaseType argument was not on the approved list");

    }

    @Override
    public boolean isSupportedIncrementerType(String incrementerType) {
        for (DatabaseType type : DatabaseType.values()) {
            if (type.name().equals(incrementerType.toUpperCase())) {
                return true;
            }
        }

        return false;
    }

    @Override
    public String[] getSupportedIncrementerTypes() {

        List<String> types = new ArrayList<String>();

        for (DatabaseType type : DatabaseType.values()) {
            types.add(type.name());
        }

        return types.toArray(new String[types.size()]);
    }
}
